<?php
namespace my;
use think\Db;
class AlipayPc{

    private $config,$puclicdata,$filtParam=[];

    /**
     * 初始化
     * @param array $config
     *  $config['partner'] 开发者编号
     *  string $config['alipay_public_key'] 支付宝公钥文件
     *  string $config['private_key'] 证书私钥
     *  string $config['seller_email']  卖家邮箱
     *  string $config['notify_url'] 页面通知地址[禁止带get参数]
     *  string $config['sign_type'] 加密类型:md5|rsa MD5加密必需传md5key,rsa必需传alipay_public_key与private_key
     */
    function __construct($config=array())
    {
        $this->config=array(
            'partner'				=>	'2088721142454730',
            'sign_type'				=>	'RSA',
            '_input_charset'		=>	strtolower('UTF-8'),
            'seller_email'	        =>	'wuguodong@hstwkj.com',
            'alipay_public_key'		=>	'alipay_public_key.pem',
            'private_key'	        =>	'tw_private_key.pem',
            'public_key'            =>  '',
            'pay_url'				=>	'https://mapi.alipay.com/gateway.do?',
            'notify_url'            =>  '',
            'return_url'            =>  '',
            'md5key'                =>  'anrr44y1h8w6n76qmhi9umyrid8htx0y',
            'it_b_pay'              =>  '15m',
        );
        $zfb_account = Db::name("sys")->where("k","zfb_account")->value('v');
        switch ($zfb_account) {
          case 1:
            $this->config['partner'] = '2088721142454730';
            $this->config['seller_email'] = 'wuguodong@hstwkj.com';
            $this->config['alipay_public_key'] = 'alipay_public_key.pem';
            $this->config['private_key'] = 'tw_private_key.pem';
            $this->config['md5key'] = 'anrr44y1h8w6n76qmhi9umyrid8htx0y';
            $this->config['it_b_pay'] = '15m';
            break;
          case 2:
            #对应配置
          default:
            break;
        }

        //加密时需要过滤的参数
        $this->filtParam=["sign","sign_type"];

        //加载配置
        $this->config($config);

    }

    /**
     * 成功返回
     */
    public function success()
    {
        return "success";
    }

    /**
     * 成功返回
     */
    public function error()
    {
        return "error";
    }

    /**
     * 设置生成加密串需要忽略的参数
     * @param array $Param
     */
    public function filt_Param($Param=[]){
        if(gettype($Param)=="array" && count($Param)>0)
        {
            $this->filtParam=array_merge($this->filtParam,$Param);
        }
    }


    /**
     * 设置配置
     * @param array $config
     *  $config['partner'] 开发者编号
     *  string $config['alipay_public_key'] 支付宝公钥文件
     *  string $config['private_key'] 证书私钥
     *  string $config['seller_id'] 卖家账号
     *  string $config['notify_url'] 页面通知地址[禁止带get参数]
     *  string $config['sign_type'] 加密类型:md5|rsa MD5加密必需传md5key,rsa必需传alipay_public_key与private_key
     */
    public function config($config=array())
    {
        if(gettype($config) && count($config)>0){
            foreach($config as $key=>$val)
            {
                if(array_key_exists($key,$this->config) && gettype($val)=="string" && $val!=''){
                    $this->config[$key]=(string)$val;
                }
            }
        }
        $this->puclicdata=array();
        $this->publicdata();
    }


    /**
     * 发起支付
     * @param number $money 支付的金额以元为单位，精确到分
     * @param string $subject 产品名称
     * @param string $orderno 订单号
     * @param string $comments 备注
     */
    public function pay($money=0,$orderno='',$subject='消费',$comments="消费")
    {
        $data= array(
            'service'				=>	'create_direct_pay_by_user',
            'out_trade_no'			=>	$orderno,
            'subject'				=>	$subject,
            'payment_type'			=>	'1',
            'seller_email'		    =>	$this->config['seller_email'],
            'total_fee'				=>	$money,
            'body'					=>	$comments,
            '_input_charset'        =>   $this->config['_input_charset'],
        );
        $data= array_merge($data,$this->publicdata);

        $data['sign']				=	$this->sign($data);

        $this->_log($data,'pay');

        return [
            'type'=>'content',
            'data'=>$this->buildRequestForm($data,'post','正在发起支付宝支付，请稍候..'),
        ];
    }

    /**notice**
     *开始通知
     */
    public function notice()
    {
        com_log([$_REQUEST],'alipaynotice');
        $this->_log($_REQUEST,"notice");

        $data=array(
            "code"=>1, #0|成功，1|有错误
            'msg'=>'success', #返回给第三方的信息
            'data'=>array(
                'out_trade_no'=>'', #要处理的订单号
                'total_fee'=>0, #用户支付的金额
                'buy_info'=>'', #打款用户的呢称
                'pay_data'=>'',#第三方订单号
            ),
        );


        if(count($_REQUEST)==0){
            $data['msg']="参数不完整";
            return $data;
        }

        //通知校验
        if($this->notice_check($_REQUEST,$this->g("sign")))
        {
            if($this->g('trade_status')!='' && $this->g('out_trade_no')!='' && $this->g('total_fee')!='')
            {
                //开始业务处理
                if($this->g('trade_status')=='TRADE_SUCCESS')
                {
                    $data['code']=0;
                    $data['data']['out_trade_no']=$this->g("out_trade_no");
                    $data['data']['total_fee']=$this->g("total_fee");
                    $data['data']['buy_info']=$this->g("buyer_email");
                    $data['data']['pay_data']=json_encode($_REQUEST,JSON_UNESCAPED_UNICODE);
                }
            }
            else
            {
                $data['msg']= 'trade_status,out_trade_no,total_fee其中一项为空';
            }
        }
        else
        {
            $data['msg']="签名错误";
        }
        return $data;
    }

    /**
     * 返回发起支付表单
     * @param array $para
     * @param string $method
     * @param string $button_name
     * @return string
     */
    private function buildRequestForm($para=[], $method="post", $button_name="正在发起支付,请稍等...") {
        //待请求参数数组

        $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='{$this->config["pay_url"]}_input_charset={$this->config['_input_charset']}'  method='".$method."'>\r\n";

        unset($para['_input_charset']);
        while (list ($key, $val) = each ($para)) {
            $sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>\r\n";
        }

        //submit按钮控件请不要含有name属性
        $sHtml = $sHtml."<input type='submit' value='".$button_name."'></form>";

        $sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";

        return $sHtml;
    }

    /**
     * 加载支付插件配置
     */
    private function publicdata()
    {

        $this->publicdata=array(
            'partner'			=>	$this->config['partner'],
            '_input_charset'	=>	$this->config['_input_charset'],
            'sign_type'			=>	$this->config['sign_type'],
            'sign'				=>	'',
            'notify_url'		=>	$this->config['notify_url'],
            'return_url'        =>  $this->config['return_url'],
            'it_b_pay'          =>  '15m',
        );
    }


    /**
     * 通知效验
     * @param array $data
     * @param $sign 要验证的签名
     */
    private function notice_check($data=array(),$sign='')
    {
        $data=$this->filt_arg($data);
        $str= $this->bulid_param($data);
        if($str!='')
        {
            switch($this->config['sign_type'])
            {
                case "MD5":
                    $result=($sign==md5($str.$this->config['md5key']));
                    break;
                default:
                    $result=$this->rsaVerify($str,$this->config['alipay_public_key'],$sign);
                    break;
            }
            return $result;
        }
        return false;
    }


    /**生成签名
     * @param string $data
     * @param string $keyfile
     * @return string
     */
    private function sign($data)
    {

        $data=$this->filt_arg($data);
        $oldStr=$str= $this->bulid_param($data);

        if($str!='')
        {
            switch($this->config['sign_type'])
            {
                case "MD5":
                    $str= md5($str.$this->config['md5key']);
                    break;
                default:
                    $str= $this->rsaSign($str);
                    break;
            }
        }

        return $str;
    }

    /**RSA-私钥加密
     * @param $data
     * @param string $keyfile
     * @return string
     */
    private function rsaSign($data,$keyfile='')
    {
        if($keyfile=='') $keyfile=__DIR__.'/rsa/'.$this->config['private_key'];
        $priKey = file_get_contents($keyfile);
        $res = openssl_get_privatekey($priKey);
        openssl_sign($data, $sign, $res);
        openssl_free_key($res);
        //base64编码
        return base64_encode($sign);
    }


    /**
     * 准备参与签名的数组
     * @param array $data
     */
    private function filt_arg($data=array())
    {
        //参数过滤
        if(count($this->filtParam)>0)
        {
            foreach($this->filtParam as $key=>$val)
            {
                if(isset($data[$val])) unset($data[$val]);
            }
        }
        return $data;
    }



    /**组装参数
     * @param array $data 传入的字符
     * @return string 返回值
     */
    private function bulid_param($data=array(),$urlencode=false)
    {
        $str='';
        ksort($data);
        reset($data);
        foreach($data as $key=>$val)
        {
            if(gettype($val)!='array' && $val!='')
            {
                if($str!='') $str.="&";
                $str.="$key=".($urlencode?urlencode($val):$val);
            }
        }
        return $str;
    }


    /**
     * 获取返回时的签名验证结果
     * @param $para_temp 通知返回来的参数数组
     * @param $sign 返回的签名结果
     * @return 签名验证结果
     */
    private function getSignVeryfy($para_temp, $sign)
    {
        $para_temp=$this->filt_arg($para_temp);
        $para_temp = $this->bulid_param($para_temp);
        return $this->rsaVerify($para_temp, trim($this->config['alipay_public_key']), $sign);
    }


    /** RSA验签
     * @param  $data 待签名数据
     * @param $ali_public_key_path 支付宝的公钥文件路径
     * @param $sign 要校对的的签名结果
     * @return 验证结果
     */
    private function rsaVerify($data, $ali_public_key_path, $sign)
    {
        $ali_public_key_path  = __DIR__.'/rsa/'.$ali_public_key_path;
        $pubKey = file_get_contents($ali_public_key_path);
        $res = openssl_get_publickey($pubKey);
        $dstr='';
        openssl_public_encrypt($sign,$dstr, $res);
        $result =(bool)openssl_verify($data,base64_decode($sign), $res);
        openssl_free_key($res);
        return $result;
    }



    /**
     * 获取传的值
     * @param string $key
     * @param string $default
     */
    private function g($key="",$default="")
    {
        $val=array_key_exists($key,$_REQUEST)?$_REQUEST[$key]:$default;
        return $val;
    }


    public function reback(){

    }

    public function checkOrder(){

    }

    /**
     * 日志
     * @param unknown $data
     */
    public function _log($data=[],$m='pay'){
        return;
        if(gettype($data)=='array' && count($data)>0)
        {
            $str="\r\n-------------------------------------------------------------[$m]".date("Y-m-d H:i:s")."----------\r\n";
            foreach($data as $key=>$val)
            {
                $str.="$key:$val\r\n";
            }
            file_put_contents(__DIR__."/".date("Ymd")."_log.txt", $str,FILE_APPEND);
        }

    }
}
